package com.brotherly.util.downloader;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

import com.brotherly.framework.app.BaseApplication;
import com.brotherly.framework.event.EventService;
import com.umeng.analytics.MobclickAgent;

public class Downloader
{
    private String urlstr;// 下载的地址
    private String localfile;// 保存路径
    private String filename;// 文件名
    private int threadcount;// 线程数
    private EventService eventService;// 消息处理器
    private DBUtil dao;// 工具类
    private int fileSize;// 所要下载的文件的大小
    private List<DownloadInfo> infos;// 存放下载信息类的集合
    private static final int INIT = 1;// 定义三种下载的状态：初始化状态，正在下载状态，暂停状态
    public static final int DOWNLOADING = 2;
    public static final int PAUSE = 3;
    public boolean isStopForce = false;

    private int state = INIT;

    public Downloader(String urlstr, String localfile, String fileName, int threadcount, Context context,
            EventService eventService)
    {
        this.urlstr = urlstr;
        this.localfile = localfile;
        this.threadcount = threadcount;
        this.eventService = eventService;
        this.filename = fileName;
        dao = DBUtil.getInstance();
    }

    public void setFileSize(int fileSize)
    {
        this.fileSize = fileSize;
    }

    public String getUrl()
    {
        return this.urlstr;
    }

    /**
     * 判断是否正在下载
     */
    public boolean isdownloading()
    {
        return (state == DOWNLOADING || state == PAUSE);
    }

    /**
     * 得到downloader里的信息 首先进行判断是否是第一次下载，如果是第一次就要进行初始化，并将下载器的信息保存到数据库中
     * 如果不是第一次下载，那就要从数据库中读出之前下载的信息（起始位置，结束为止，文件大小等），并将下载信息返回给下载器
     */
    public LoadInfo getDownloaderInfors(int fileSize)
    {
        if (isFirst(urlstr))
        {
            init();
            if (fileSize != 0)
                this.fileSize = fileSize;
            int range = this.fileSize / threadcount;
            infos = new ArrayList<DownloadInfo>();
            for (int i = 0; i < threadcount - 1; i++)
            {
                DownloadInfo info = new DownloadInfo(i, i * range, (i + 1) * range - 1, 0, urlstr, filename, 0);
                infos.add(info);
            }
            // 不明白这里未什么要1
            // DownloadInfo info = new DownloadInfo(threadcount - 1,
            // (threadcount - 1) * range, fileSize - 1, 0, urlstr);
            DownloadInfo info = new DownloadInfo(threadcount - 1, (threadcount - 1) * range, this.fileSize, 0, urlstr,
                    filename, 0);
            infos.add(info);
            // 保存infos中的数据到数据库
            dao.saveInfos(infos);
            // 创建一个LoadInfo对象记载下载器的具体信息
            LoadInfo loadInfo = new LoadInfo(this.fileSize, 0, urlstr);
            return loadInfo;
        } else
        {
            // 得到数据库中已有的urlstr的下载器的具体信息
            infos = dao.getInfos(urlstr);
            // Log.v("TAG", "not isFirst size=" + infos.size());
            int size = 0;
            int compeleteSize = 0;
            for (DownloadInfo info : infos)
            {
                compeleteSize += info.getCompeleteSize();
                // 不明白这里未什么加1
                // size += info.getEndPos() - info.getStartPos() +1 ;
                size += info.getEndPos() - info.getStartPos() + 1;
            }
            this.fileSize = size;
            return new LoadInfo(size, compeleteSize, urlstr);
        }
    }

    /**
      */
    private void init()
    {
        try
        {
            File file = new File(localfile);
            if (!file.exists())
            {
                file.createNewFile();
            }
            // 本地访问文件
            RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
            accessFile.setLength(fileSize);
            accessFile.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 判断是否是第一次 下载
     */
    private boolean isFirst(String urlstr)
    {
        return dao.isHasInfors(urlstr);
    }

    /**
     * 114 * 利用线程开始下载数据 115
     */
    public void download()
    {
        if (infos != null)
        {
            if (state == DOWNLOADING)
                return;
            state = DOWNLOADING;
            for (DownloadInfo info : infos)
            {
                eventService.signEvent(DownLoaderUtil.Activity_Event_FileDownload_Start, 1, info.getUrl());
                new MyThread(info.getThreadId(), info.getStartPos(), info.getEndPos(), info.getCompeleteSize(), info.getUrl())
                        .start();
            }
        }
    }

    @Override
    public String toString()
    {
        return this.urlstr;
    }

    public class MyThread extends Thread
    {
        private int threadId;
        private int startPos;
        // private int endPos;
        private int completeSize;
        private String urlstr;

        public MyThread(int threadId, int startPos, int endPos, int compeleteSize, String urlstr)
        {
            this.threadId = threadId;
            this.startPos = startPos;
            // this.endPos = endPos;
            this.completeSize = compeleteSize;
            this.urlstr = urlstr;
        }

        @Override
        public void run()
        {
            HttpURLConnection connection = null;
            RandomAccessFile randomAccessFile = null;
            InputStream is = null;
            try
            {
                URL url = new URL(urlstr);
                Log.i("TAG", "Download file :" + urlstr);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(30000);
                connection.setRequestMethod("GET");
                // 设置范围，格式为Range：bytes x-y;
                if (startPos + completeSize > 1)
                {
                    // + endPos
                    connection.setRequestProperty("Range", "bytes=" + (startPos + completeSize) + "-");
                }
                int serversize = connection.getContentLength();
                if (serversize != -1 && serversize + startPos != fileSize)
                {
                    fileSize = serversize + startPos + completeSize;
                }
                Log.i("TAG", "Download file :" + localfile);
                randomAccessFile = new RandomAccessFile(localfile, "rwd");
                randomAccessFile.seek(startPos + completeSize);
                // 将要下载的文件写到保存在保存路径下的文件中
                is = connection.getInputStream();
                byte[] buffer = new byte[20480];
                // int length = buffer.length;

                long begin = System.currentTimeMillis();
                int length = is.read(buffer, 0, buffer.length);
                if (length == -1)
                {
                    throw new Exception();
                }
                while (length != -1)
                {
                    randomAccessFile.write(buffer, 0, length);
                    completeSize += length;
                    // 更新数据库中的下载信息
                    dao.updataInfos(threadId, fileSize, completeSize, urlstr);
                    // 用消息将下载信息传给进度条，对进度条进行更新
                    JSONObject json = new JSONObject();
                    json.put("compelete", completeSize);
                    json.put("url", urlstr);
                    json.put("filename", filename);
                    json.put("localfile", localfile);
                    json.put("fileSize", fileSize);
                    if (completeSize >= fileSize
                            || System.currentTimeMillis() - begin > 3000)
                    {
                        begin = System.currentTimeMillis();
                        if (!isStopForce)
                            eventService.signEvent(DownLoaderUtil.Activity_Event_FileDownload_Info, 1, json);
                        if (completeSize >= fileSize)
                        {
                            if (!isStopForce)
                            {
                                MobclickAgent.onEvent(BaseApplication.getInstance().getApplicationContext(), "DownloadFinish");
                                // dao.updateComplete(urlstr);
                                DownLoaderUtil dUtil = DownLoaderUtil.getInstence(BaseApplication.getInstance());
                                dUtil.stopDownload(urlstr);
                                BaseApplication.getInstance().checkInstallApk(json);
                                break;
                            }
                        }
                    }
                    if (isStopForce)
                    {
                        break;
                    }
                    if (state == PAUSE && completeSize < fileSize)
                    {
                        if (!isStopForce)
                            eventService.signEvent(DownLoaderUtil.Activity_Event_FileDownload_Pause, 1, urlstr);
                        break;
                    }
                    length = is.read(buffer, 0, buffer.length);
                    Thread.sleep(10);
                }

            }
            catch (Exception e)
            {
                e.printStackTrace();
                if (!isStopForce)
                    eventService.signEvent(DownLoaderUtil.Activity_Event_FileDownload_Info, 0, urlstr);
            }
            finally
            {
                try
                {
                    is.close();
                    randomAccessFile.close();
                    connection.disconnect();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }

        }
    }

    // 设置暂停
    public void pause()
    {
        state = PAUSE;
    }

    // 重置下载状态
    public void reset()
    {
        state = INIT;
    }

    public int getState()
    {
        return state;
    }
}
